﻿using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NetPay.WeChat;

namespace MiPeiPei.Utility.Pay.WeChat
{
	public class HttpClientHelper : DelegatingHandler
    {
        /// <summary>
        /// 商户ID
        /// </summary>
        private readonly string merchantId;
        /// <summary>
        /// 商户私钥
        /// </summary>
        private readonly string serialNo;

        public HttpClientHelper(string merchantId, string merchantSerialNo)
        {
            InnerHandler = new HttpClientHandler();

            this.merchantId = merchantId;
            this.serialNo = merchantSerialNo;
        }

        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var auth = await BuildAuthAsync(request);
            string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
            request.Headers.Add("Authorization", value);

            var resp = await base.SendAsync(request, cancellationToken);
            string resp_body = await resp.Content.ReadAsStringAsync();

            return resp;
        }

        protected async Task<string> BuildAuthAsync(HttpRequestMessage request)
        {
            string method = request.Method.ToString();
            string body = "";
            if (method == "POST" || method == "PUT" || method == "PATCH")
            {
                var content = request.Content;
                body = await content.ReadAsStringAsync();
            }

            string uri = request.RequestUri.PathAndQuery;
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = Path.GetRandomFileName();

            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = Sign(message);
            return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }

        protected static string Sign(string message)
        {
            var path = System.Environment.CurrentDirectory + "/wwwroot/apiclient_cert.p12";
            X509Certificate2 cert = new X509Certificate2(path, Config.MCHID, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
            var privateKey = cert.PrivateKey.ToXmlString(true);

            using (RSACryptoServiceProvider sha256 = new RSACryptoServiceProvider())
            {
                byte[] dataInBytes = Encoding.UTF8.GetBytes(message);
                sha256.FromXmlString(privateKey);
                byte[] inArray = sha256.SignData(dataInBytes, CryptoConfig.MapNameToOID("SHA256"));
                string sign = Convert.ToBase64String(inArray);
                return sign;
            }
        }
    }
}

